/**
 * Copyright (C) 2010-2016 eBusiness Information, Excilys Group
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed To in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package org.ohosannotations.internal;

import org.ohosannotations.handler.AnnotationHandler;
import org.ohosannotations.handler.GeneratingAnnotationHandler;
import org.ohosannotations.handler.HasParameterHandlers;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.ohosannotations.handler.AnnotationHandler;
import org.ohosannotations.handler.GeneratingAnnotationHandler;
import org.ohosannotations.handler.HasParameterHandlers;

/**
 * AnnotationHandlers
 *
 * @since 2021-07-20
 */
public class AnnotationHandlers {
    private List<AnnotationHandler<?>> annotationHandlers = new ArrayList<>();
    private List<GeneratingAnnotationHandler<?>> generatingAnnotationHandlers = new ArrayList<>();
    private List<AnnotationHandler<?>> decoratingAnnotationHandlers = new ArrayList<>();
    private Set<String> supportedAnnotationNames;

    /**
     * 构造参数
     */
    public AnnotationHandlers() {
    }

    /**
     * add
     *
     * @param annotationHandler 注解处理者
     */
    public void add(AnnotationHandler<?> annotationHandler) {
        annotationHandlers.add(annotationHandler);
        if (annotationHandler instanceof GeneratingAnnotationHandler) {
            generatingAnnotationHandlers.add((GeneratingAnnotationHandler) annotationHandler);
        } else {
            decoratingAnnotationHandlers.add(annotationHandler);
        }
        addParameterHandlers(annotationHandler);
    }

    private void addParameterHandlers(AnnotationHandler<?> annotationHandler) {
        if (annotationHandler instanceof HasParameterHandlers) {
            HasParameterHandlers<?> hasParameterHandlers = (HasParameterHandlers<?>) annotationHandler;
            for (AnnotationHandler<?> parameterHandler : hasParameterHandlers.getParameterHandlers()) {
                add(parameterHandler);
            }
        }
    }

    /**
     * get
     *
     * @return List集合
     */
    public List<AnnotationHandler<?>> get() {
        return annotationHandlers;
    }

    /**
     * getGenerating
     *
     * @return List 集合
     */
    public List<GeneratingAnnotationHandler<?>> getGenerating() {
        return generatingAnnotationHandlers;
    }

    /**
     * getDecorating
     *
     * @return List集合
     */
    public List<AnnotationHandler<?>> getDecorating() {
        return decoratingAnnotationHandlers;
    }

    /**
     * getSupportedAnnotationTypes
     *
     * @return supportedAnnotationNames
     */
    public Set<String> getSupportedAnnotationTypes() {
        if (supportedAnnotationNames == null) {
            Set<String> annotationNames = new HashSet<>();
            for (AnnotationHandler annotationHandler : annotationHandlers) {
                annotationNames.add(annotationHandler.getTarget());
            }
            supportedAnnotationNames = Collections.unmodifiableSet(annotationNames);
        }
        return supportedAnnotationNames;
    }

    /**
     * getGeneratingAnnotations
     *
     * @return generatingAnnotations
     */
    @SuppressWarnings("unchecked")
    public List<Class<? extends Annotation>> getGeneratingAnnotations() {
        List<Class<? extends Annotation>> generatingAnnotations = new ArrayList<>();
        for (GeneratingAnnotationHandler generatingAnnotationHandler : getGenerating()) {
            try {
                generatingAnnotations.add((Class<? extends Annotation>) Class
                    .forName(generatingAnnotationHandler.getTarget()));
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return generatingAnnotations;
    }
}
